#ifndef TC_AUTOPTR_HPP
#define TC_AUTOPTR_HPP

/** \file AutoPtr.hpp
 * Declarations for the class template AutoPtr.
 *
 * (C) Copyright  Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * Inspired by Nicholai Josuttis' auto_ptr implementation.
 *
 * $Id: AutoPtr.hpp 117 2006-06-19 06:49:41Z semihc $
 *
 *
 */

#include "Global.hh"

namespace TC {


  //! Auxiliary type to enable copies and assignments (now global)
  template <typename Y>
  struct AutoPtrRef 
  {
    // TYPES
    typedef Y ElementType;
    typedef AutoPtrRef<Y> ClassType;
    // CREATORS
    AutoPtrRef (Y* ptr) : m_ptr(ptr) {}
    // MEMBERS
    Y* m_ptr;
  };


  /**
   * Improved, standard conforming, auto_ptr equivalent
   * class template definition.
   */
  template <typename T>
  class AutoPtr 
  {
  public:
    // TYPES
    typedef T ElementType;
    typedef AutoPtr<T> ClassType;

    // CREATORS
    // Constructor
    explicit AutoPtr(T* ptr = 0) //throw()
      : m_ptr(ptr) {}

    // Copy constructors (with implicit conversion)
    // - note: nonconstant parameter
    AutoPtr(AutoPtr& rhs) //throw()
      : m_ptr(rhs.release()) {}
    
    template<class Y>
    AutoPtr(AutoPtr<Y>& rhs) //throw()
      : m_ptr(rhs.release()) {}

    // To enable copies and assignment with AutoPtrRef
    AutoPtr(AutoPtrRef<T> rhs) //throw()
      : m_ptr(rhs.m_ptr) {}

    // Destructor
    ~AutoPtr() //throw() 
    { delete m_ptr; }


    // ACCESSORS
    // Value access
    T* get() const //throw()
    { return m_ptr; }
    
    T& operator*() const //throw() 
    { return *m_ptr; }

    T* operator->() const //throw() 
    { return m_ptr; }


    // MODIFIERS
    // Release ownership
    T* release() //throw() 
    {
      T* tmp(m_ptr);
      m_ptr = 0;
      return tmp;
    }

    // Reset value
    void reset(T* ptr=0) //throw() 
    {
      if(m_ptr != ptr) {
        delete m_ptr;
        m_ptr = ptr;
      }
    }

    // Assignments (with implicit conversion)
    // - note: nonconstant parameter
    AutoPtr& operator=(AutoPtr& rhs) //throw() 
    {
      reset(rhs.release());
      return *this;
    }
      
    template<class Y>
    AutoPtr& operator=(AutoPtr<Y>& rhs) //throw() 
    {
      reset(rhs.release());
      return *this;
    }
        


    //
    // Special conversions with AutoPtrRef to enable copies and assignments
    //
    
    // New
    AutoPtr& operator=(AutoPtrRef<T> rhs) //throw()
    {
      reset(rhs.m_ptr);
      return *this;
    }
    
    template<class Y>
    operator AutoPtrRef<Y>() //throw() 
    { return AutoPtrRef<Y>(release()); }
    
    template<class Y>
    operator AutoPtr<Y>() //throw() 
    { return AutoPtr<Y>(release()); }


  private:
    // MEMBERS
    // Refers to the actual owned object (if any)
    T* m_ptr;    

  }; // end class


} // end namespace


#endif /* Include guard */
